home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-20 / rs0422.zip / ROSEZSW / UPCALLS.C < prev   
C/C++ Source or Header  |  1990-08-04  |  17KB  |  658 lines

  1. /*
  2.  * Copyright 1988 by the Radio Amateur Telecommunications Society
  3.  * and Thomas A. Moulton, W2VY
  4.  *
  5.  * This software may only be modified, copied, distributed or
  6.  * executed for non-profit purposes by individuals operating
  7.  * systems in the Amateur Radio Service.  Credit to the
  8.  * author(s) and to the Radio Amateur Telecommunications Society
  9.  * must be made in modules where RATS provided software is used,
  10.  * and in any announcements and documentation.  
  11.  *
  12.  * As a non-profit, research and development organization,  the
  13.  * Radio Amateur Telecommunications Society distributes software
  14.  * in both executable and source forms.  This policy is in place
  15.  * to encourage the development and distribution of OSI-based,
  16.  * networking tools.  In order to protect the interests of the
  17.  * Society and the authors, we have placed some conditions
  18.  * of use on the software.  Other groups are encouraged
  19.  * to place the same or similar guidelines on
  20.  * software they produce.
  21.  *
  22.  * The Radio Amateur Telecommunications Society reserves the right
  23.  * to specify and alter the terms under which software provided by
  24.  * the Society may be used.  This policy is consistent with the 
  25.  * objective of uniform and consistent "Open Systems Interconnections."
  26.  * 
  27.  * All acceptable Amateur Radio related uses of this software
  28.  * will be outlined in the "ROSE Implementer's Guide".  Individuals
  29.  * or organizations wishing to add to, or modify the provisions of
  30.  * the guide to accommodate local or evolutionary requirements
  31.  * should document the proposed change(s) and forward them to the
  32.  * Society.  If accepted, written notification will be provided by
  33.  * the Society to the submitting organization or individual(s).
  34.  * The Society will then issue a "ROSE Implementer's Guide Change
  35.  * Notice".  Periodically, the Society will re-issue the "ROSE 
  36.  * Implementer's Guide" and incorporate the text of the change 
  37.  * notices.  This procedure has been put in to place to ensure
  38.  * compatibility between systems and to ensure their "Openness"
  39.  * and interoperability.
  40.  *
  41.  * No part of this software may be used in other packages 
  42.  * without prior authorization from the author or the Society.  
  43.  * Software incorporating this module, all or in part, must be 
  44.  * provided to the Society prior to distribution or use by
  45.  * anyone not directly involved in testing of the revised  
  46.  * environment.  Current releases of the combined software must
  47.  * be provided to the Society in both source and executable
  48.  * forms.  Adequate documention to produce an executable module 
  49.  * from the provided source must also be included.
  50.  *
  51.  * Non-Amateur Radio non-profit uses may be authorized on a case
  52.  * by case basis.  Inquiries for such use may be made in writing
  53.  * to the Society. Non-commercial uses consistent with the
  54.  * general principles of Open Systems Interconnection Reference
  55.  * Model will be generally considered with favor.
  56.  *
  57.  * Commercial licensing of the software is also available based
  58.  * on normal commercial terms.  Licensing inquiries should be
  59.  * directed to the Society.  Commercial licensing of the standard
  60.  * software will be done in situations which materially benefit
  61.  * the Amateur Radio Packet Network.  Additional licensing is
  62.  * reserved by the individual authors.
  63.  * 
  64.  * The Radio Amateur Telecommunications Society provides this software
  65.  * on an "as is" basis.  The Society assumes no liability for
  66.  * loss incurred through the use of this software.  Amateur Radio
  67.  * use of this software implies non-commercial and voluntary 
  68.  * development, deployment and use of this software in a "Amateur",
  69.  * non-commercial service.  Commercial users are encouraged to
  70.  * inspect their copies of the source code.  Source code modification
  71.  * licenses are available if a combined Object and Source Code
  72.  * license was not originally established.
  73.  * 
  74.  * The Society may be contacted by writing or calling at:
  75.  * 
  76.  * The Radio Amateur Telecommunications Society 
  77.  * 206 North Vivyen Street.
  78.  * Bergenfield, New Jersey 07621
  79.  *
  80.  * Telephone: 201-387-8896
  81.  *
  82.  */
  83. #include "data.h"
  84. #include "buffer.h"
  85. #include "iface.h"
  86. #include "timer.h"
  87. #include "ax25.h"
  88. #include "ax25l2.h"
  89. #include "l3struc.h"
  90. #include "x25cause.h"
  91. #include "l3calls.h"
  92. #include "tx.h"
  93.  
  94. extern unsigned char node_addr[16];
  95. extern unsigned char str_work[128];
  96. extern struct datastr *l2_user_info;    /* The message to send dummies */
  97. extern struct ax25_addr L3CALL[];
  98. extern unsigned char L3_MAXVC[];
  99. #define L3SIZ 32
  100.  
  101. void rx_up_ignore(), tx_up_flush(), level3(), del_ax25();
  102. int st_up_wait();
  103. extern struct ax25_parms *l2parms, *l3parms;
  104. extern unsigned char call_num;
  105. int l2_clear(), l2_reset(), l2_send(), l2_recv(), NULLFCN();
  106. struct datastr *mkpkt();
  107. void rsrtco(), lnk_ign_fcn(), vc_clear();
  108.  
  109. int
  110. lnk_cauz(axcb)
  111. register struct axcb *axcb;
  112. {
  113.     return ((axcb->parms->retry&&!axcb->n2cnt) ? Congestion+146 : DTE_Orig);
  114. }
  115.  
  116. int
  117. l2_st_up(axcbx, oldstate, newstate)
  118. struct axcb *axcbx;            /* Link         */
  119. unsigned char oldstate, newstate;    /* Old and new states    */
  120. {
  121.     register struct VCS *vc;
  122.     static struct VCS *vcp;
  123.     static struct axcb *axcb;
  124.     static int c;
  125.     static unsigned char a, b;
  126.     struct VCS *new_vcs();
  127.     int callcmp();
  128.  
  129.     axcb=axcbx;
  130.  
  131.     puthex2("l2st",axcb,"->",newstate);
  132.     vc=axcb->llcn;
  133.     vcp= (vc ? vc->peer : (struct VCS *)NULL);
  134.     if ((newstate == 0) && vc) /* Link Reset */ {
  135.         if (vc->P == P4) /* Call in Data Transfer */ {
  136.             vc_reset(vc, DTE_Orig+146);
  137.         }
  138.         else tnc_attempt(axcb,vcp);
  139.     }
  140.     else {
  141.        if (newstate == 5) /* Connect occurred */ {
  142.         if (oldstate == 2) /* We made the call, notify peer */ {
  143.             if (vc) set_p(vc,P4,0); /* have a vc */
  144.         } 
  145.         else if (oldstate == 1) /* Connect request */ {
  146.             if (!(vc=new_vcs())) return 0; /* No memory */
  147.             vcp=vc->peer;
  148.             vc->parent=axcb;
  149.             vc->lcn=0;
  150.             axcb->llcn = vc;    /* insert_lcn(vc); */
  151.             vc_l2_pars(vc);
  152.             str_work[0]=0;
  153.             a=1;
  154.             b=0;
  155.             c=3;
  156.             do {
  157.                 if (callcmp(&axcb->path[a],&L3CALL[0])) b=1;
  158.                 if (callcmp(&axcb->path[a],&L3DIGI[0])) b=2;
  159.                 if (b) /* If either callsign used */ {
  160.                     str_work[0]=0;
  161.                     l3_adr(&axcb->path[a-1],str_work);
  162.                     if (str_work[0] == 4) /* Was DNIC */ {
  163.                         l3_adr(&axcb->path[a-2],str_work);
  164.                         c++;
  165.                     }
  166.                     if (!str_work[0]) /*Failed*/ {
  167.                         free(vcp);
  168.                         free(vc);
  169.                         axcb->llcn = NULL;
  170.                         return 0;
  171.                     }
  172.                     if (!(axcb->path[a].ssid&E)) /*More*/ {
  173.                         memcpy(&vc->digi,&axcb->path[a+1],AXALEN);
  174.                     }
  175.                     if (a==c) /* Have destination digi */ {
  176.                         memcpy(&vcp->digi,&axcb->path[1],AXALEN);
  177.                     }
  178.                     adr_copy(0,str_work,0,vcp->addr);
  179.                 /*    adr_copy(0,node_addr,0,vc->addr); */
  180.                     break;
  181.                 }
  182.             } while ( !(axcb->path[a++].ssid & E));
  183.  
  184.             if (!b) return 0;    /* Never Entered Loop */
  185.             mk_nsap(vcp,&axcb->myaddr);
  186.             mk_nsap(vc,axcb->path);
  187.             mk_rand(vc);
  188.             vcp->alt = 255;    /* First time through call_request */
  189.             vc->P = P2;    /* This link is in Call Request */
  190.             if (b == 2) vc->flags = vcp->flags = CLRONRESET;
  191.             tnc_attempt(axcb, vcp);    /* Give message */
  192.            }
  193.         }
  194.         else {
  195.             if (newstate == 1) /* Disconnect occurred */ {
  196.                 if (vcp) /* Have peer */ {
  197.                     c = DTE_Orig;
  198.                     if (axcb->parms->retry&& !axcb->n2cnt) {
  199.                         c = Congestion+146;
  200.                          if (oldstate == 2) c=Ship_Absent;
  201.                     } else if (oldstate == 2) c=Number_Busy;
  202.                 /*    (*vc->CLEAR)(vc, DTE_Orig); */
  203.                     set_p(vc, P7, c);
  204.                 }
  205.                 del_ax25(axcb);
  206.             }
  207.         }
  208.     }
  209.     return 1;
  210. }
  211.  
  212. /* l3_rx_up => see Level3.c, level3() */
  213. /* l3_tx_up => not used, may want to insure no vc's are flow controlled */
  214.  
  215. l3_st_up(lnk,oldstate,newstate)
  216. register struct axcb *lnk;
  217. unsigned char oldstate, newstate;
  218. {
  219.     static struct VCS *vc, *lvc;
  220.     static int c;
  221.     unsigned char i;
  222.     void rx_up_wait();
  223.     int route_fail();
  224.  
  225.     puthex2("l3st",lnk,"->",newstate);
  226.     if (newstate == 0) /* Link Reset */ {
  227.         if (lnk->R == R1) {
  228.             lvc = lnk->llcn;
  229.             while (lvc) /* More vc's to reset */ {
  230.                 vc=lvc;
  231.                 lvc=lvc->next;
  232.                 if (vc->P == P4) vc_reset(vc, Net_Congest+146);
  233.                 else vc_clear(vc, Congestion+146);
  234.             }
  235.         } else /* Link Reset during L3 Restart */ {
  236.             if (lnk->R != R0) /* Restart again */ {
  237.                 rsrtco(lnk);
  238.                 lnk->R = R0;
  239.                 lnk->coll=0;
  240.             } else if (lnk->link_num == 0) {
  241.                 queue(&lnk->t20,rx_up_wait, COLLTIME, lnk);
  242.             }
  243.         }
  244.     }
  245.     else {
  246.         if (newstate == 5) /* Connected */ {
  247.             lnk->R=R0;
  248.             lnk->coll=0;
  249.             if ((i=lnk->link_num) != 0) /* Level 3 Link */ {
  250.                 if (i < L3SIZ) lnk->maxvc=L3_MAXVC[i];
  251.                 queue(&lnk->t20 ,rsrtco ,(oldstate == 1) ? COLLTIME : 0 ,lnk);
  252.             }
  253.             else /* Level 2 User, wait for PID (in I frame) */ {
  254.                 lnk->r_upcall=rx_up_wait;
  255.                  /* Give L3 User 60 Sec to sent restart */
  256.                 queue(&lnk->t20 ,rx_up_wait ,COLLTIME ,lnk);
  257.             }
  258.         }
  259.         else {
  260.             if (newstate == 1) /* Disconnect occurred */ {
  261.                 c = Out_of_Order;
  262.                 if (lnk->parms->retry && !lnk->n2cnt) {
  263.                     c = Congestion+146;
  264.                 } else if (lnk->rpid != PID_X25) c += 33;
  265.                 while (vc=lnk->llcn) /* For all VC's */ {
  266.                     vc_clear(vc,c);
  267.                 }
  268.                 c = lnk->link_num;
  269.                 del_ax25(lnk);
  270.                 route_fail(c); /* Advance pending calls if we can */
  271.             }
  272.         }
  273.     }
  274.     return 1;
  275. }
  276.  
  277. void
  278. rx_up_wait(axcb)
  279. register struct axcb *axcb;
  280. {
  281.     static struct datastr *p;
  282.     struct datastr *frag_pkt();
  283.     void level3();
  284.  
  285.     kill(axcb->t20);    /* Timer timed out, or isn't needed anymore */
  286.     if (axcb->rpid != PID_X25) /* Users don't listen to directions!! */ {
  287.         rx_up_ignore(axcb);
  288.         lnk_ign_fcn(axcb);
  289.         axcb->parms=l2parms;
  290.         p=frag_pkt(dup_pkt(l2_user_info), l2parms->framesize);
  291.         l2_copy(axcb, &p, 0x7fff);
  292.     }
  293.     else /* Hey! We've got a new Level 3 User!! */ {
  294.         lnk_l3_pars(axcb);
  295.     /*    l3_st_up(axcb,1,5);    /* Force into connected state */
  296.         level3(axcb);        /* Process the data we received */
  297.     }
  298. }
  299.  
  300. void
  301. rx_up_ignore(axcb)
  302. struct axcb *axcb;
  303. {
  304.     static struct datastr *p;
  305.  
  306.     recv_ax25(axcb,&p,0); /* Throw away the data */
  307.     free_pkt(p);
  308. }
  309.  
  310. void
  311. tx_up_flush(axcb)
  312. register struct axcb *axcb;
  313. {
  314.     if ( (axcb->iqueue == NULL) || (axcb->icnt <= 0) ) /* All done! */ {
  315.         close_ax25(axcb);
  316.     }
  317. }
  318.  
  319. int
  320. st_up_wait(axcb,old,new)
  321. struct axcb *axcb;
  322. unsigned char old,new;
  323. {
  324.     puthex2("wait",axcb,"->",new);
  325.     if (new == 1) /* We are done!! */ {
  326.         del_ax25(axcb);
  327.     }
  328.     return 1;
  329. }
  330.  
  331. int
  332. NULLFCN() {}
  333.  
  334. struct datastr *
  335. l_message(str, v)
  336. char *str;
  337. int v;
  338. {
  339.     register struct datastr *p;
  340.  
  341.     if ((p=mkpkt(str)) == NULL) return NULL;
  342.     putxch(p,(v>>8));
  343.     putxch(p,(v&0xff));
  344.     bappch(p,0x0d);
  345.     return p;
  346. }
  347.  
  348. int
  349. send_l3(vc, bp)
  350. struct VCS *vc;
  351. struct datastr *bp;
  352. {
  353.     if (vc && vc->SEND) return (*vc->SEND)(vc, bp);
  354.     else free_pkt(bp);
  355.     return 0;
  356. }
  357.  
  358. int
  359. l3_reset(vc,diag)
  360. struct VCS *vc;
  361. unsigned int diag;
  362. {
  363.     puthex2("l3reset",vc,"",diag);
  364.     tx_rst(vc, DTE_Orig+diag);
  365. }
  366.  
  367. int
  368. l2_reset(vc,diag) 
  369. struct VCS *vc;
  370. unsigned int diag;
  371. {
  372.     static struct axcb *lnk;
  373.  
  374.     set_d(vc, D1, 0);
  375.     if ((lnk=vc->parent)) {
  376.         axconnect(lnk);
  377.         send_tnc(lnk,l_message("\r*** Reset *** ", diag));
  378.     }
  379. }
  380.  
  381.  
  382. int
  383. l3_clear(vc,c)
  384. register struct VCS *vc;
  385. int c;
  386. {
  387.     /* This should only set P1 if no parent, see l3_st_up re: CLRONRESET */
  388.     if (vc->parent) tx_clr(vc,c);
  389.     else set_p(vc, P1, 0);
  390.     /* Insert code to generate call clear records here */
  391. }
  392.  
  393. int
  394. l3_connected(vc)
  395. struct VCS *vc;
  396. {
  397.     /* Insert code to generate call records here */
  398. }
  399.  
  400. int
  401. l2_clear(vc,c)
  402. struct VCS *vc;
  403. unsigned int c;
  404. {
  405.     register struct axcb *lnk;
  406.  
  407.     lnk=vc->parent;
  408.     set_p(vc,P1,0);
  409.     if (!lnk) return;    /* No link exists */
  410.     lnk_ign_fcn(lnk);
  411.  
  412.     if (lnk->state < 3) close_ax25(lnk);
  413.     else send_tnc(lnk,l_message("\r*** Disconnect *** ", c));
  414. }
  415.  
  416. tnc_attempt(axcb, vcp)
  417. struct axcb *axcb;
  418. register struct VCS *vcp;
  419. {
  420.     extern char being_set[];
  421.  
  422.     send_tnc(axcb, mkpkt(
  423.         (vcp->alt && !(vcp->flags & CLRONRESET) && vcp->P == P1) ?
  424.         being_set : "") );
  425. }
  426.  
  427. int
  428. l2_con(vc)
  429. register struct VCS *vc;
  430. {
  431.     static struct datastr *bp;
  432.     static struct axcb *axcb;
  433.     static unsigned char *ch;
  434.     int call_str(), x121_str();
  435.     extern char complete[];
  436.     void l2_rx_up();
  437.  
  438. /*    if (vc) if (vc->RECV) (*vc->RECV)(vc,NULL); */
  439.     axcb = vc->parent;
  440.     if (!vc->alt && !(vc->flags & CLRONRESET) && axcb) {
  441.         bp = mkpkt(complete);
  442.         ch = &str_work[call_str(&vc->parent->myaddr, str_work)];
  443.         *ch++ = ' ';
  444.         *ch++ = '@';
  445.         *ch++ = ' ';
  446.         ch += x121_str(vc->peer->addr, ch);
  447.         *ch++ = 0x0d;
  448.         *ch = 0;
  449.         bappstr(bp,str_work);
  450.         send_tnc(axcb, bp);
  451.     }
  452.     queue(NULL, l2_rx_up, 0, axcb);
  453. }
  454.  
  455. int
  456. l2_send(vcx, px)
  457. struct VCS *vcx;
  458. struct datastr *px;
  459. {
  460.     register struct axcb *lnk;
  461.     static struct VCS *vc;
  462.     static int frsiz, windo;
  463.  
  464.     vc_queue_data((vc=vcx),px);        /* We were passed data */
  465.     if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
  466.     lnk=vc->parent;
  467.  
  468.     frsiz = lnk->parms->framesize;
  469.     windo = frsiz * lnk->parms->maxframe;    /* Number of bytes I can send */
  470.  
  471.     l2_copy(lnk, &vc->tx_queue, windo);
  472.     if (lnk->window <= lnk->icnt) return 0;    /* Can't accept any more now */
  473.  
  474.     return frsiz;    /* Return what we can take now */
  475. }
  476.  
  477. l2_copy(lnk, bpq, w)
  478. struct axcb *lnk;
  479. register struct datastr **bpq;
  480. int w;
  481. {
  482.     static struct datastr *p;
  483.  
  484.     while (p = *bpq) /* More to send */ {
  485.         if (w <= lnk->icnt) return;
  486.         *bpq = p->next;
  487.         p->next=NULL;
  488.         send_tnc(lnk,p);
  489.     }
  490. }
  491.  
  492. int
  493. l2_recv(vcx,pkt)
  494. struct VCS *vcx;
  495. struct datastr *pkt;
  496. {
  497.     register struct VCS *vcp;
  498.     static struct VCS *vc;
  499.     static struct axcb *lnk;
  500.     static struct datastr *p;
  501.     static int i;
  502.     int recv_ax25();
  503.  
  504.     vc=vcx;
  505.     if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
  506.     lnk=vc->parent;
  507.     if ((vcp=vc->peer)) /* Have a peer */ {
  508.         i = send_l3(vcp,NULL);
  509.         vc->LBUSY = !i;
  510.         while (!vc->LBUSY) /* And they can take more! */ {
  511.             if (recv_ax25(lnk,&p,i) <= 0) break;
  512.             i = send_l3(vcp,p);
  513.             vc->LBUSY = !i;
  514.         }
  515.     }
  516. }
  517.  
  518. int
  519. l3_send(vc,px)
  520. register struct VCS *vc;
  521. struct datastr *px;
  522. {
  523.     static struct axcb *lnk;
  524.     static struct datastr *p, *p1;
  525.     static int frsiz, i;
  526.  
  527.     puthex2("l3tx P",vc->P,"busy",vc->RBUSY);
  528.     vc_queue_data(vc,(p=px));    /* We have data to send */
  529.     if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
  530.     lnk=vc->parent;
  531.     if (vc->RBUSY) return 0;    /* We are flow controlled */
  532.     while ( vc->tx_queue &&        /* We have data to send AND */ 
  533.        ((vc->LIPR + vc->WI - vc->OPS) % 8) > 0 ) /* Window is open */ {
  534.         i= (vc->OPS << 1) + (vc->OPR << 5);
  535.         if ((p1=new_buffer(3)) == NULL) break;    /* No memory */
  536.         bappch(p1,0x10); /* GFI=1 LCGN=0 */
  537.         bappch(p1,vc->lcn);
  538.         bappch(p1,i); /* p(r) 0 p(s) 0 Packet type */
  539.         p=vc->tx_queue;
  540.         vc->tx_queue=p->next;
  541.         p->next=NULL;
  542.         p1=binsert(p1,p);
  543.         l2_tx(lnk,p1); /* Send the frame */
  544.         vc->OPS = (vc->OPS +1) % 8;
  545.     }
  546.     frsiz=lnk->parms->framesize;
  547.     if (((vc->LIPR + vc->WI - vc->OPS) % 8) > 0 ) /* Window open */ i=frsiz;
  548.     else i=0;    /* Window Closed can't take any more */
  549.     return i;
  550. }
  551.  
  552. int
  553. l3_recv(vc, pkt)
  554. register struct VCS *vc;
  555. struct datastr *pkt;
  556. {
  557.     static char lbusy;
  558.  
  559.     puthex2("l3rx",vc,"",pkt);
  560.     if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
  561.     lbusy=vc->LBUSY;
  562.     vc->LBUSY = !send_l3(vc->peer, pkt);
  563.     if (lbusy && !vc->LBUSY) tx_rr(vc);    /* Just got un-busy */
  564. }
  565.  
  566. void
  567. l2_rx_up(axcb)
  568. struct axcb *axcb;
  569. {
  570.     register struct VCS *vc;
  571.  
  572.     if (vc=axcb->llcn) (*vc->RECV)(vc,NULL);    /* Have a vc */
  573. }
  574.  
  575. void
  576. l2_tx_up(axcb)
  577. struct axcb *axcb;
  578. {
  579.     register struct VCS *vc;
  580.     void call_request();
  581.  
  582.     if (vc=axcb->llcn) if (vc=vc->peer) {
  583.         if (vc->P == P1 &&    /* Source user connection setup */
  584.            vc->alt == 255 &&    /* Hasn't been through call_request */
  585.            !axcb->icnt) {    /* Message is ack'ed */
  586.             queue(&vc->peer->timer,call_request,0,vc);
  587.         }
  588.         else (*vc->RECV)(vc,NULL);
  589.     }
  590. }
  591.  
  592. vc_l2_pars(vc)
  593. register struct VCS *vc;
  594. {
  595.     extern int (*L2PARS[])();
  596.  
  597.     bmove(&L2PARS, &vc->RESET, 5*sizeof(vc->RESET));
  598. #if 0
  599. 11/1/89    vc->RESET=l2_reset;
  600.     vc->CLEAR=l2_clear;
  601.     vc->SEND=l2_send;
  602.     vc->RECV=l2_recv;
  603.     vc->CONNECTED=l2_con;
  604. #endif
  605. }
  606.  
  607. lnk_l3_pars(lnk)
  608. register struct axcb *lnk;
  609. {
  610.     static int i;
  611.     int l2_window(), find_call();
  612.  
  613.     lnk->parms=l3parms;
  614.     lnk->r_upcall=level3;
  615.     lnk->t_upcall=NULLFCN;
  616.     lnk->s_upcall=l3_st_up;
  617.     lnk->window=l2_window(l3parms);
  618.     i = find_call(&lnk->path[0]);
  619.     if (i>0 && L3_MAXVC[i]) {
  620.         lnk->link_num = i;
  621.         lnk->rpid = PID_X25;
  622.     }
  623. }
  624.  
  625. void
  626. lnk_ign_fcn(lnk)
  627. register struct axcb *lnk;
  628. {
  629.     lnk->r_upcall=rx_up_ignore;
  630.     lnk->t_upcall=tx_up_flush;
  631.     lnk->s_upcall=st_up_wait;
  632. }
  633.  
  634. void
  635. vc_clear(vc,c)
  636. register struct VCS *vc;
  637. int c;
  638. {
  639.     if (vc->peer) {
  640.         vc->peer->peer = NULL;
  641.         set_p(vc->peer,P6,c);
  642.         vc->peer = NULL;
  643.     }
  644.     set_p(vc,P1,0);
  645. }
  646.  
  647. int
  648. vc_reset(vc, c)
  649. register struct VCS *vc;
  650. int c;
  651. {
  652.     static unsigned char flag;
  653.  
  654.     flag = vc->flags;    /* This CAN call P6 if CLRONRESET is set */
  655.     set_d(vc,D3, c);
  656.     if (!(flag&CLRONRESET)) set_d(vc,D1, 0);
  657. }
  658.